﻿using System;
using System.Diagnostics;
using System.Resources;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using JiveMessenger.Resources;
using Windows.Devices.Geolocation;
using System.Linq;
using System.Threading;
using System.Windows.Threading;
using System.Collections.Generic;
using Microsoft.Phone.Notification;
using JiveMessenger.CustomControls;
using System.IO.IsolatedStorage;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using JiveMessenger.Network;
using GalaSoft.MvvmLight.Messaging;
using JiveMessenger.Helpers;
using JiveMessenger.Settings;
using JiveMessenger.ViewModels;
using Microsoft.Phone.Info;
using JmShared;
using JiveMessenger.User;
using System.Reflection;
using DeviceStatus = JmShared.DeviceStatus;
using System.Threading.Tasks;
namespace JiveMessenger
{
    public partial class App : Application
    {
        /// <summary>
        /// Provides easy access to the root frame of the Phone Application.
        /// </summary>C:\Users\Ole\documents\visual studio 2012\Projects\Jive\Jive\Resources\
        /// <returns>The root frame of the Phone Application.</returns>
        private Thread _lockscreenThread;
        private DispatcherTimer _receiptTimer;
        private Dictionary<int, KeyValuePair<DateTime, ChatMessage>> _sentMessages;
        private object ReceiveEmoticonLockObject = new object();
        private Dictionary<UserInfo, List<string>> _emoticonExistCache;
        public static PhoneApplicationFrame RootFrame { get; private set; }
        public static NetworkConnection Connection { get; set; }


        public static int unreadMsgCount { get; set; }







        /// Constructor for the Application object.
        /// </summary>
        public App()
        {
            // Global handler for uncaught exceptions.
            UnhandledException += Application_UnhandledException;

            // Standard XAML initialization
            InitializeComponent();

            // Phone-specific initialization
            InitializePhoneApplication();

            // Language display initialization
            InitializeLanguage();
            // Show graphics profiling information while debugging.
            if (Debugger.IsAttached)
            {
                // Display the current frame rate counters.
                Application.Current.Host.Settings.EnableFrameRateCounter = true;

                // Show the areas of the app that are being redrawn in each frame.
                //Application.Current.Host.Settings.EnableRedrawRegions = true;

                // Enable non-production analysis visualization mode,
                // which shows areas of a page that are handed off to GPU with a colored overlay.
                //Application.Current.Host.Settings.EnableCacheVisualization = true;

                // Prevent the screen from turning off while under the debugger by disabling
                // the application's idle detection.
                // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
                // and consume battery power when the user is not using the phone.
                PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
            }
            _emoticonExistCache = new Dictionary<UserInfo, List<string>>();
            Messenger.Default.Register<Uri>(this, (u) => RootFrame.Navigate(u));

            _sentMessages = new Dictionary<int, KeyValuePair<DateTime, ChatMessage>>();
            AppSettings.AppSettingsInstance.PropertyChanged += AppSettings_PropertyChanged;
            Connection = new NetworkConnection(GetUniqueId(), Assembly.GetExecutingAssembly().GetName().Version.ToString());
            InitReceiptTimer();
            //Connection.ChatMessageReceived += Connection_ChatMessageReceived;
            //Connection.ChatMessageSendt += Connection_ChatMessageSendt;
            //Connection.ChatReceiptReceived += Connection_ChatReceiptReceived;
            //Connection.OnDisconnected += Connection_OnDisconnected;

            //Connection.HostnameLookupSucceeded += Connection_HostnameLookupSucceeded;
            //Connection.MessageQueueItemReceived += Connection_MessageQueueItemReceived;
            AttachEvents(Connection);

            Messenger.Default.Register<NotificationMessage>(this, msg =>
            {
                switch (msg.Notification)
                {
                    case "UpdateCustomEmoticons":
                        //CreateCustomEmoticonList();
                        WpUserSettings settings = new WpUserSettings
                        {
                            CustomEmoticons = Client.Instance.UserSettings.CustomEmoticons
                        };
                        Connection.SendUserSettings(settings);
                        //var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
                        //viewModelLocator.ViewModelMainPage.CreateCustomEmoticons();
                        break;
                }
            });
        }

        private void AttachEvents(NetworkConnection connection)
        {
            connection.ChatMessageReceived += Connection_ChatMessageReceived;
            connection.ContactEmoticonReceived += Connection_ContactEmoticonReceived;
            connection.ChatMessageSendt += Connection_ChatMessageSendt;
            connection.ClientListReceived += Connection_ClientListReceived;
            connection.ChatReceiptReceived += Connection_ChatReceiptReceived;
            connection.OnDisconnected += Connection_OnDisconnected;
            connection.UserSettingsReceived += Connection_UserSettingsReceived;
            connection.ServerInfoMessageReceived += Connection_ServerInfoMessageReceived;
            connection.DeviceStatusReceived += Connection_DeviceStatusReceived;
            connection.HostnameLookupSucceeded += Connection_HostnameLookupSucceeded;
        }




        private void DetachEvents(NetworkConnection connection)
        {
            connection.ChatMessageReceived -= Connection_ChatMessageReceived;
            connection.ContactEmoticonReceived -= Connection_ContactEmoticonReceived;
            connection.ChatMessageSendt -= Connection_ChatMessageSendt;
            connection.ClientListReceived -= Connection_ClientListReceived;
            connection.ChatReceiptReceived -= Connection_ChatReceiptReceived;
            connection.OnDisconnected -= Connection_OnDisconnected;
            connection.UserSettingsReceived -= Connection_UserSettingsReceived;
            connection.ServerInfoMessageReceived -= Connection_ServerInfoMessageReceived;
            connection.DeviceStatusReceived -= Connection_DeviceStatusReceived;
            connection.HostnameLookupSucceeded -= Connection_HostnameLookupSucceeded;
        }

        private void Connection_ContactEmoticonReceived(object sender, ContactEmoticonEventArgs e)
        {
            ReceiveEmoticon(e.Emoticon);
        }

        private void Connection_UserSettingsReceived(object sender, UserSettingsEventArgs e)
        {
            Client.Instance.SetUserSettings(e.Settings);
        }

        private void Connection_DeviceStatusReceived(object sender, DeviceStatusEventArgs e)
        {

            DeviceStatus status = e.Status;
            UserInfo info;
            if (Client.Instance.ConnectedClients.TryGetValue(status.UserID, out info))
            {
                info.ClientStatus = status.ClientStatus.GetValueOrDefault(ClientStatus.Available);
                Deployment.Current.Dispatcher.BeginInvoke(() => AddOrUpdateUsers(info));
            }
        }

        private void Connection_ClientListReceived(object sender, ClientListEventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke((() => this.AddOrUpdateUsers(e.ClientList.Clients)));
        }

        private void Connection_ServerInfoMessageReceived(object sender, ServerInfoMessageEventArgs e)
        {
            ServerInfoMessage msg = e.Message;
            switch (msg.MessageType)
            {
                case ServerInfoMessageType.UserInfoUpdated:
                    {
                        UserInfo user = msg.UserInfo;
                        Deployment.Current.Dispatcher.BeginInvoke((() => this.AddOrUpdateUsers(user)));
                        break;
                    }
                case ServerInfoMessageType.LoginFailed:
                    {
                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            Messenger.Default.Send("Wrong username or password.");
                            Client.Instance.CurrentUserInfo = null;
                        });
                        break;
                    }
                case ServerInfoMessageType.LoginSuccessful:
                    {
                        UserInfo user = msg.UserInfo;
                        Client.Instance.CurrentUserInfo = user;

                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
                            viewModelLocator.ViewModelMainPage.RunOnNetworkConnect();
                            AddOrUpdateUsers(user);
                            _receiptTimer.Start();
                        });

                        _sentMessages = new Dictionary<int, KeyValuePair<DateTime, ChatMessage>>();

                        Client.Instance.IsLoggedIn = true;

                        Thread t = new Thread(() =>
                        {
                            App.ResetTileCount();
                            App.RegisterPush(true, AppSettings.AppSettingsInstance.IsToastNotificationEnabledSetting);

                        }) { IsBackground = true };

                        t.Start();
                        this.DisplayGroupMessage(user, user.PrettyName + " has been added to the conversation.", msg.MessageType, DateTime.Now);

                        //if (LoginSuccessful != null)
                        //    LoginSuccessful(this, null);
                        // this.DisplayGroupMessage(Client.GreenText, "Login successful", msg.MessageType, msg.MessageRelayTime);

                        // BroadcastEmoticons();

                        break;
                    }
                case ServerInfoMessageType.Authenticated:
                    {
                        UserInfo user = msg.UserInfo;

                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            AddOrUpdateUsers(user);
                            if (Client.Instance.ConnectedClients.Values.ToList().FindAll(x => x.UserName == user.UserName).Count == 1)
                                this.DisplayGroupMessage(user, user.PrettyName + " has been added to the conversation.", msg.MessageType, DateTime.Now);
                        });
                        break;
                    }
                case ServerInfoMessageType.ContactDisconnected:
                    {
                        Deployment.Current.Dispatcher.BeginInvoke((Action)(() => RemoveUser(msg.UserInfo.UserID)));
                        //SetPmWindowStatus(msg.UserInfo.UserID);
                        break;
                    }
            }
        }
        void Connection_MessageQueueItemReceived(object sender, MessageQueueUpdateEventArgs e)
        {
            var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
            viewModelLocator.ViewModelMainPage.MessageQueueItemReceivedCommand.Execute(e);
        }

        void Connection_HostnameLookupSucceeded(object sender, HostnameLookupEventArgs e)
        {
            if (AppSettings.AppSettingsInstance.HostnameCache == null)
                AppSettings.AppSettingsInstance.HostnameCache = new Dictionary<string, string>();

            AppSettings.AppSettingsInstance.HostnameCache[AppSettings.AppSettingsInstance.ServerSetting] = e.IPAddress;
        }

        void Connection_OnDisconnected(object sender, EventArgs e)
        {

            if (Client.Instance.IsLoggedIn)
            {
                if (Client.Instance.CurrentUserInfo != null)
                    DisplayGroupMessage(Client.RedText, Client.Instance.CurrentUserInfo.PrettyName + " has left the conversation!", MessageType.Logout, DateTime.Now);
            }
            Client.Instance.IsLoggedIn = false;
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
                viewModelLocator.ViewModelMainPage.RunOnNetworkDisconnect();
                viewModelLocator.ViewModelPrivateMessagePage.RunOnNetworkDisconnect();
                _receiptTimer.Stop();
            });
        }

        void Connection_ChatReceiptReceived(object sender, ChatReceiptEventArgs e)
        {
            AcknowledgeSendtMessageReceipt(e.Receipt.MessageID);
        }

        void Connection_ChatMessageSendt(object sender, ChatMessageEventArgs e)
        {
            ChatMessage msg = e.Message;
            if (msg.MessageType == MessageType.GroupMessage || msg.MessageType == MessageType.PrivateMessage)
            {
                _sentMessages.Add(msg.MessageID.Value, new KeyValuePair<DateTime, ChatMessage>(DateTime.Now, msg));
            }
        }
        private void InitReceiptTimer()
        {
            _receiptTimer = new DispatcherTimer();
            _receiptTimer.Interval = new TimeSpan(0, 0, 3);
            _receiptTimer.Tick += _receiptTimer_Tick;
        }
        private void _receiptTimer_Tick(object sender, EventArgs e)
        {
            List<int> toRemove = new List<int>();
            foreach (var v in _sentMessages)
            {
                if (DateTime.Now.Subtract(v.Value.Key).TotalSeconds > 6)
                {
                    DisplayGroupMessage(Client.RedText, String.Format("Message response timeout. It is possible the message was not received: {0}", v.Value.Value.Message), MessageType.Error, DateTime.Now);
                    toRemove.Add(v.Key);
                }
            }
            foreach (int i in toRemove)
                _sentMessages.Remove(i);
        }
        private void AcknowledgeSendtMessageReceipt(int id)
        {
            this._sentMessages.Remove(id);
        }
        void Connection_ChatMessageReceived(object sender, ChatMessageEventArgs e)
        {
            ChatMessage msg = e.Message;

            if (Client.Instance.ConnectedClients.ContainsKey(msg.SenderID))
                msg.SenderInfo = Client.Instance.ConnectedClients[msg.SenderID];
            switch (msg.MessageType)
            {
                //case MessageType.LoginFailed:
                //    {
                //        Deployment.Current.Dispatcher.BeginInvoke(() =>
                //        {
                //            Messenger.Default.Send("Wrong username or password.");
                //        });
                //        break;
                //    }
                //case MessageType.LoginSuccessful:
                //    {
                //        UserInfo user = StaticMethods.StringToObject<UserInfo>(msg.Message);
                //        Client.ClientInstance.CurrentUserInfo = user;

                //        Deployment.Current.Dispatcher.BeginInvoke(() =>
                //        {
                //            var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
                //            viewModelLocator.ViewModelMainPage.RunOnNetworkConnect();
                //            AddOrUpdateUsers(user);
                //            _receiptTimer.Start();
                //        });

                //        _sentMessages = new Dictionary<int, KeyValuePair<DateTime, ChatMessage>>();

                //        Client.ClientInstance.IsLoggedIn = true;

                //        Thread t = new Thread(() =>
                //        {
                //            App.ResetTileCount();
                //            App.RegisterPush(true, AppSettings.AppSettingsInstance.IsToastNotificationEnabledSetting);

                //        }) { IsBackground = true };

                //        t.Start();


                //        //if (LoginSuccessful != null)
                //        //    LoginSuccessful(this, null);
                //        this.DisplayGroupMessage(Client.GreenText, "Login successful", msg.MessageType, msg.MessageRelayTime);

                //        BroadcastEmoticons();

                //        break;
                //    }
                //case MessageType.Authenticated:
                //    {
                //        UserInfo user = StaticMethods.StringToObject<UserInfo>(msg.Message);

                //        Deployment.Current.Dispatcher.BeginInvoke(() =>
                //        {
                //            AddOrUpdateUsers(user);
                //            if (Client.ClientInstance.ConnectedClients.Values.ToList().FindAll(x => x.UserName == user.UserName).Count == 1)
                //                this.DisplayGroupMessage(Client.GreenText, user.PrettyName + " has been added to the conversation.", msg.MessageType, msg.MessageRelayTime);
                //        });
                //        BroadcastEmoticons();
                //        break;
                //    }
                case MessageType.GroupMessage:
                    {
                        Deployment.Current.Dispatcher.BeginInvoke(() => this.DisplayGroupMessage(msg));
                        break;
                    }
                case MessageType.PrivateMessage:
                    {
                        Deployment.Current.Dispatcher.BeginInvoke((Action)(() => ProcessPM(msg)));
                        break;
                    }
                //case MessageType.Hello:
                //    {
                //        Deployment.Current.Dispatcher.BeginInvoke((Action)(() => this.AddOrUpdateUsers(StaticMethods.StringToObject<UserInfo[]>(msg.Message))));
                //        break;
                //    }
                //case MessageType.UpdateUserInfo:
                //    {
                //        Deployment.Current.Dispatcher.BeginInvoke((Action)(() => this.AddOrUpdateUsers(StaticMethods.StringToObject<UserInfo>(msg.Message))));
                //        break;
                //    }
                //case MessageType.Logout:
                //    {
                //       Deployment.Current.Dispatcher.BeginInvoke((Action)(() => RemoveUser(msg.Recipients)));
                //        break;
                //    }
                //case MessageType.Busy:
                //case MessageType.AFK:
                //    {
                //        UserInfo user = StaticMethods.StringToObject<UserInfo>(msg.Message);
                //        Deployment.Current.Dispatcher.BeginInvoke(() => AddOrUpdateUsers(user));

                //        break;
                //    }
                //case MessageType.BroadcastEmoticons:
                //    {

                //        ProcessCustomContactEmoticons(msg);
                //        break;
                //    }
                case MessageType.RequestEmoticon:
                    {
                        if (!StaticSettings.IsWifiEnabled)
                            return;//don't transfer emoticon images without wifi

                        //if (!StaticSettings.CustomEmoticons.ContainsKey(msg.Message))
                        //    break;
                        //if (String.IsNullOrEmpty(StaticSettings.CustomEmoticons[msg.Message]))
                        //    break;
                        var imgArray = StaticMethods.LoadImageAsByteArray(Client.Instance.UserSettings.CustomEmoticons[msg.Message]);
                        var ce = new ContactEmoticon
                        {
                            KeyWord = msg.Message,
                            EmoticonByteArray = imgArray,
                            Extension = Path.GetExtension(Client.Instance.UserSettings.CustomEmoticons[msg.Message]),
                            SenderID = Client.Instance.CurrentUserInfo.UserID
                            //RecipientIDs = new string[] { msg.SenderID }
                        };
                        Connection.SendEmoticon(ce);
                        //ContactEmoticon ce = new ContactEmoticon
                        //{
                        //    KeyWord = msg.Message,
                        //    EmoticonByteArray = StaticMethods.LoadImageAsByteArray(StaticSettings.GetEmoticons(Client.ClientInstance.CurrentUserInfo.UserID, true, true)[msg.Message])
                        //};
                        //msg.Message = StaticMethods.ContactEmoticonToString(ce);
                        //msg.MessageType = MessageType.SendingEmoticon;
                        ////UserInfo receiver = msg.Sender;
                        //msg.Recipients = new string[1];
                        //msg.Recipients[0] = msg.SenderID;
                        //msg.SenderID = Client.ClientInstance.CurrentUserInfo.UserID;
                        //Connection.SendMessage(msg);
                        break;
                    }
                //case MessageType.SendingEmoticon:
                //    {
                //        ReceiveEmoticon(msg);
                //        break;
                //    }
            }
        }
        private void DisplayGroupMessage(UserInfo sender, string messageText, MessageType mt, DateTime timestamp, string recipientID)
        {
            ChatMessage msg = new ChatMessage(sender.UserID, mt, messageText, recipientID)
            {
                SenderInfo = sender,
                MessageRelayTime = timestamp,
            };
            Deployment.Current.Dispatcher.BeginInvoke(() => DisplayGroupMessage(msg));
        }
        private void DisplayGroupMessage(UserInfo sender, string messageText, ServerInfoMessageType mt, DateTime timestamp)
        {
            ServerInfoMessage msg = new ServerInfoMessage
            {
                MessageType = mt,
                Message = messageText,
                UserInfo = sender
            };
            Deployment.Current.Dispatcher.BeginInvoke(() => DisplayGroupMessage(msg));
        }
        private void DisplayGroupMessage(ChatMessage msg)
        {

            var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
            foreach (ViewModelGroupChat vm in viewModelLocator.ViewModelMainPage.ChatViewModels.Where(x => x.GetType() == typeof(ViewModelGroupChat) && x.ID == msg.RecipientID))
            {
                UserInfo sender = msg.SenderInfo ?? Client.Instance.ConnectedClients[msg.SenderID];
                ((ViewModelGroupChat)vm).DisplayMessage(msg);
            }
        }
        private void DisplayGroupMessage(ServerInfoMessage msg)
        {
            var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
            foreach (ViewModelGroupChat vm in viewModelLocator.ViewModelMainPage.ChatViewModels.Where(x => x.GetType() == typeof(ViewModelGroupChat) && msg.UserInfo.ChatGroups.Any(y => y.ID == x.ID)))
            {
                UserInfo sender = Client.Instance.CurrentUserInfo;
                ((ViewModelGroupChat)vm).DisplayMessage(msg);
            }
        }
        //private void DisplayGroupMessage(ChatMessage msg)
        //{

        //        var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
        //        viewModelLocator.ViewModelMainPage.AddMessage(msg);

        //}
        ///// <summary>
        ///// Broadcast your custom emoticons
        ///// </summary>
        //private void BroadcastEmoticons()
        //{
        //    Connection.SendStatusMessage(MessageType.BroadcastEmoticons, StaticMethods.ListToString<string>(StaticSettings.CustomEmoticons.Keys.ToList()));
        //}
        private void DisplayGroupMessage(UserInfo sender, string messageText, MessageType mt, DateTime timestamp)
        {
            ChatMessage msg = new ChatMessage(sender.UserID, mt)
            {
                Message = messageText,
                SenderInfo = sender,
                MessageRelayTime = timestamp
            };
            Deployment.Current.Dispatcher.BeginInvoke(() => DisplayGroupMessage(msg));

        }
        private void AddOrUpdateUsers(UserInfo user)
        {
            //Deployment.Current.Dispatcher.BeginInvoke(() =>
            //{
            if (user.ChatGroups == null)
                user.ChatGroups = new ChatGroup[] { };
            UserInfo oldUser;
            if (Client.Instance.ConnectedClients.TryGetValue(user.UserID, out oldUser))
            {
                //this means we have it, so we just go through the properties and update what we can.
                var userInfoProperties = oldUser.GetType().GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
                foreach (var prop in userInfoProperties)
                {
                    var value = prop.GetValue(user, null);
                    var attributes = prop.GetCustomAttributes(typeof(UserInfoAttribute), false);
                    if (attributes.Length > 0)
                    {
                        UserInfoAttribute att = attributes[0] as UserInfoAttribute;
                        if (att == null)
                            continue;

                        else if (value != null)
                        {
                            if (att.PropertyType == UserInfoAttributeType.Avatar)
                            {
                                if (((byte[])value).Length == 0)
                                    value = null;
                            }
                            prop.SetValue(oldUser, value, null);
                        }
                    }
                }
            }
            else
                Client.Instance.ConnectedClients.Add(user.UserID, user);

            user = Client.Instance.ConnectedClients[user.UserID];
            var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
            if (user.Equals(Client.Instance.CurrentUserInfo))
            {
                if (user.Notifications != null)
                {
                    viewModelLocator.ViewModelNotificationsPage.Notifications.Clear();
                    foreach (var n in user.Notifications)
                    {
                        viewModelLocator.ViewModelNotificationsPage.Notifications.Add(n);
                    }
                }
            }
            else
            {
                ProcessCustomContactEmoticons(user);
            }


            viewModelLocator.ViewModelMainPage.AddOrUpdateContact(user);

            //});
            //if (UserAddedOrUpdated != null)
            //    UserAddedOrUpdated(this, new UserAddedEventArgs(user));
        }
        private void AddOrUpdateUsers(UserInfo[] users)
        {
            foreach (UserInfo user in users)
            {
                AddOrUpdateUsers(user);
            }
            List<UserInfo> foo = new List<UserInfo>(Client.Instance.ConnectedClients.Values);
            foreach (var user in foo)
            {
                if (!users.Contains(user) && !user.Equals(Client.Instance.CurrentUserInfo))
                {
                    Client.Instance.ConnectedClients.Remove(user.UserID);
                    var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
                    viewModelLocator.ViewModelMainPage.Contacts.Remove(viewModelLocator.ViewModelMainPage.Contacts.FirstOrDefault(x => x.UserID == user.UserID));
                }
            }
        }

        private void RemoveUser(string userID)
        {

            var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];
            UserInfo u = null;
            if (Client.Instance.ConnectedClients.TryGetValue(userID, out u))
            {
                if (userID.Equals(Client.Instance.CurrentUserInfo.UserID)) // don't remove our own connected user.
                    return;

                Client.Instance.ConnectedClients.Remove(u.UserID);
                viewModelLocator.ViewModelMainPage.RemoveOfflineContact(u.UserName);
            }
        }
        ///// <summary>
        ///// Process other users custom emoticons.
        ///// </summary>
        ///// <param name="message"></param>
        //private void ProcessCustomContactEmoticons(ChatMessage message)
        //{
        //    Debug.WriteLine("Processing custom contact emoticons");
        //    List<string> customEmoticons = StaticMethods.StringToList<string>(message.Message);
        //    if (AppSettings.AppSettingsInstance.CustomContactEmoticons == null)
        //        AppSettings.AppSettingsInstance.CustomContactEmoticons = new Dictionary<string, Dictionary<string, string>>();
        //    foreach (string str in customEmoticons)
        //    {

        //        lock (ReceiveEmoticonLockObject)
        //        {
        //            if (!AppSettings.AppSettingsInstance.CustomContactEmoticons.ContainsKey(message.SenderID))
        //            {
        //                AppSettings.AppSettingsInstance.CustomContactEmoticons[message.SenderID] = new Dictionary<string, string>(); // List<Emoticons.ContactEmoticon>();
        //            }
        //        }
        //        bool requestEmoticon = false;
        //        if (!AppSettings.AppSettingsInstance.CustomContactEmoticons[message.SenderID].ContainsKey(str))
        //        {
        //            requestEmoticon = true;
        //        }
        //        else if (String.IsNullOrEmpty(AppSettings.AppSettingsInstance.CustomContactEmoticons[message.SenderID][str]) && StaticSettings.IsWifiEnabled) //don't request emoticons without wifi.
        //            requestEmoticon = true;
        //        if (requestEmoticon)
        //        {
        //            //save a reference to the emoticon in the library
        //            lock (ReceiveEmoticonLockObject)
        //            {
        //                if (!AppSettings.AppSettingsInstance.CustomContactEmoticons[message.SenderID].ContainsKey(str))
        //                    AppSettings.AppSettingsInstance.CustomContactEmoticons[message.SenderID].Add(str, string.Empty); //new Emoticons.ContactEmoticon { KeyWord = str });
        //            }
        //            //Send a message to the user requesting the user send the emoticon so we can save it to disk
        //            ChatMessage msg = new ChatMessage();
        //            msg.MessageType = MessageType.RequestingEmoticon;
        //            msg.Message = str;
        //            //UserInfo receiver = message.Sender;
        //            msg.SenderID = Client.ClientInstance.CurrentUserInfo.UserID;
        //            msg.Recipients = new string[1];
        //            msg.Recipients[0] = message.SenderID;
        //            Connection.SendMessage(msg);
        //            Debug.WriteLine(string.Format("Requesting emoticon for key {0}", str));
        //            Thread.Sleep(300);
        //        }
        //        else
        //            Debug.WriteLine(string.Format("Skipping emoticon request for key {0}", str));
        //    }
        //    lock (ReceiveEmoticonLockObject)
        //    {
        //        List<string> toRemove = new List<string>();
        //        if (AppSettings.AppSettingsInstance.CustomContactEmoticons.ContainsKey(message.SenderID))
        //        {
        //            foreach (KeyValuePair<string, string> kvp in AppSettings.AppSettingsInstance.CustomContactEmoticons[message.SenderID])
        //            {
        //                if (!customEmoticons.Contains(kvp.Key))
        //                    toRemove.Add(kvp.Key);
        //            }
        //        }
        //        foreach (string str in toRemove)
        //        {
        //            AppSettings.AppSettingsInstance.CustomContactEmoticons[message.SenderID].Remove(str);
        //            Debug.WriteLine(string.Format("Removed emoticon for user {0} and key {1}", message.SenderID, str));
        //        }
        //    }
        //}
        /// <summary>
        /// Process custom emoticons, and request missing images.
        /// </summary>
        /// <param name="message"></param>
        private void ProcessCustomContactEmoticons(UserInfo user)
        {
            if (user.CustomEmoticons == null)
                return;
            if (!_emoticonExistCache.ContainsKey(user))
                _emoticonExistCache[user] = new List<string>();
            Task.Factory.StartNew((obj) =>
            {

                UserInfo sender = (UserInfo)obj;
                foreach (KeyValuePair<string, string> kvp in sender.CustomEmoticons)
                {
                    bool requestEmoticon = false;
                    string keyword = kvp.Key;
                    if (!_emoticonExistCache[user].Contains(keyword))
                    {
                        requestEmoticon = IsolatedStorageFile.GetUserStoreForApplication().FileExists(StaticMethods.CombinePath(StaticSettings.CustomContactEmoticonFolder, "Icons_" + sender.UserName, kvp.Value));
                        if (!requestEmoticon)
                            _emoticonExistCache[sender].Add(keyword);
                    }
                    if (requestEmoticon)
                    {
                        //Send a message to the server requesting the emoticon so we can save it to isolated storage
                        ChatMessage msg = new ChatMessage(Client.Instance.CurrentUserInfo.UserID, MessageType.RequestEmoticon, keyword, sender.UserID);

                        Connection.SendMessage(msg);
                    }
                }
            }, user);
        }
        /// <summary>
        /// Receives a custom contact emoticon as a chatmessage, saves it to disk and stores the reference.
        /// </summary>
        /// <param name="msg"></param>
        private void ReceiveEmoticon(ContactEmoticon ce)
        {
            //UserInfo user = msg.Sender;
            UserInfo sender = Client.Instance.ConnectedClients[ce.SenderID];
            //ContactEmoticon ce = StaticMethods.StringToObject<ContactEmoticon>(msg.Message);
            Debug.WriteLine(string.Format("Received emoticon from {0} for key {1}", ce.SenderID, ce.KeyWord));
            if (String.IsNullOrEmpty(ce.KeyWord))
                return;

            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
            string savePath = StaticSettings.CustomContactEmoticonFolder;
            if (!storage.DirectoryExists(savePath))
                storage.CreateDirectory(savePath);

            savePath = StaticMethods.CombinePath(savePath, "Icons_" + sender.UserName);
            if (!storage.DirectoryExists(savePath))
                storage.CreateDirectory(savePath);

            savePath = StaticMethods.CombinePath(savePath, StaticMethods.FileNameFriendly(ce.KeyWord) + ce.Extension);
            try
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {

                    BitmapImage b = new BitmapImage();
                    b.SetSource(new MemoryStream(ce.EmoticonByteArray));
                    StaticMethods.SaveToPng(b, savePath);

                    Debug.WriteLine(string.Format("Saved emoticon from {0} for key {1} to isolated storage", ce.SenderID, ce.KeyWord));
                });

            }
            catch (IOException err)
            {
                Messenger.Default.Send(String.Format("Error saving custom emoticon from {0} : ", sender.UserName) + err.Message);
                return;
            }
            //if (AppSettings.AppSettingsInstance.CustomContactEmoticons.ContainsKey(ce.SenderID))
            //{
            //    Dictionary<string, string> cce = AppSettings.AppSettingsInstance.CustomContactEmoticons[ce.SenderID];

            //    if (cce.ContainsKey(ce.KeyWord))
            //    {
            //        cce[ce.KeyWord] = savePath;
            //        Debug.WriteLine(string.Format("Matched emoticon from {0} for key {1} to custom contact emoticon list", ce.SenderID, ce.KeyWord));
            //    }
            //}
            _emoticonExistCache[sender].Add(ce.KeyWord);
        }

        private void ProcessPM(ChatMessage msg)
        {
            UserInfo user = msg.SenderInfo;
            if (!Client.Instance.PrivateMessages.ContainsKey(user.UserName))
                Client.Instance.PrivateMessages.Add(user.UserName, new List<ChatMessage>());
            Client.Instance.PrivateMessages[user.UserName].Add(msg);

            var viewModelLocator = (ViewModelLocator)Application.Current.Resources["Locator"];

            //if (viewModelLocator.ViewModelPrivateMessagePage != null
            //    && viewModelLocator.ViewModelPrivateMessagePage.PmTarget != null
            //    && viewModelLocator.ViewModelPrivateMessagePage.PmTarget.UserName == user.UserName)
            //{
            if(viewModelLocator.ViewModelMainPage.CurrentActiveViewModel.GetType()==typeof(ViewModelPrivateMessage)
                && viewModelLocator.ViewModelMainPage.CurrentActiveViewModel.ID== user.UserName)
            {
                viewModelLocator.ViewModelMainPage.CurrentActiveViewModel.DisplayMessage(user, msg.Message, msg.MessageRelayTime.GetValueOrDefault());
            }
            else
            {
                viewModelLocator.ViewModelMainPage.IncrementContactUnreadPmCount(msg.SenderInfo.UserName);
            }
        }
        void AppSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsLockscreenDisabledSetting")
                SetLockscreenState((bool)sender);
        }


        // Code to execute when the application is launching (eg, from Start)
        // This code will not execute when the application is reactivated
        private void Application_Launching(object sender, LaunchingEventArgs e)
        {

            //Thread t = new Thread(() =>
            //{
            //    foreach (KeyValuePair<string, string> kvp in StaticSettings.CustomEmoticons)
            //    {
            //        Deployment.Current.Dispatcher.BeginInvoke(() =>
            //            {
            //                BitmapImage i = StaticMethods.LoadBitmapImageFromIsolatedStorage(kvp.Value);
            //            });
            //    }

            //});
            //t.IsBackground = true;
            //t.Start();
        }

        // Code to execute when the application is activated (brought to foreground)
        // This code will not execute when the application is first launched
        private void Application_Activated(object sender, ActivatedEventArgs e)
        {

            if (_lockscreenThread != null && _lockscreenThread.IsAlive)
                _lockscreenThread.Abort();

            _lockscreenThread = new Thread(() =>
                {
                    try
                    {
                        DeviceStatus status = new DeviceStatus(Client.Instance.CurrentUserInfo.UserID, true);
                        Connection.SendDeviceStatus(status);

                        //Connection.SendStatusMessage(MessageType.UpdateDeviceStatus, StaticMethods.ObjectToString<DeviceInfo>(new DeviceInfo
                        //{
                        //    IsActive = true,
                        //    IsTileEnabled = AppSettings.AppSettingsInstance.IsTileNotificationEnabledSetting,
                        //    IsToastEnabled = AppSettings.AppSettingsInstance.IsToastNotificationEnabledSetting,
                        //    StoreMessagesWhileOffline = AppSettings.AppSettingsInstance.StoreMessagesWhileOfflineSetting,
                        //    OfflineMessagesAgeLimit = AppSettings.AppSettingsInstance.OfflineMessageAgeLimitSetting,
                        //    OfflineMessagesCountLimit = AppSettings.AppSettingsInstance.OfflineMessageCountLimitSetting,
                        //    SendGroupPushWhileOffline = AppSettings.AppSettingsInstance.OfflinePmToastEnabledSetting,
                        //    SendPmPushWhileOffline = AppSettings.AppSettingsInstance.OfflineGroupToastEnabledSetting
                        //}));

                        Thread.Sleep(2500);

                        if (Client.Instance.IsLoggedIn)
                        {
                            ResetTileCount();
                        }
                    }
                    catch { }
                })
                {
                    Name = "ResetTileThread",
                    IsBackground = true
                };
            _lockscreenThread.Start();

            Debug.WriteLine(DateTime.Now.ToLongTimeString() + ": running in background = false");
        }

        // Code to execute when the application is deactivated (sent to background)
        // This code will not execute when the application is closing
        private void Application_Deactivated(object sender, DeactivatedEventArgs e)
        {
            //UpdateUiTimer.Stop();
            if (Client.Instance.IsLoggedIn && Connection.MasterConnectionInfo.ConnectionState == NetworkCommsDotNet.ConnectionState.Established)
            {
                try
                {
                    DeviceStatus status = new DeviceStatus(Client.Instance.CurrentUserInfo.UserID, false);
                    Connection.SendDeviceStatus(status);
                    //Connection.SendDeviceStatus(MessageType.ResetUnreadMessageCount, StaticMethods.ObjectToString<DeviceInfo>(new DeviceInfo
                    //{
                    //    IsActive = false,
                    //    IsTileEnabled = AppSettings.AppSettingsInstance.IsTileNotificationEnabledSetting,
                    //    IsToastEnabled = AppSettings.AppSettingsInstance.IsToastNotificationEnabledSetting,
                    //    StoreMessagesWhileOffline = AppSettings.AppSettingsInstance.StoreMessagesWhileOfflineSetting,
                    //    OfflineMessagesAgeLimit = AppSettings.AppSettingsInstance.OfflineMessageAgeLimitSetting,
                    //    OfflineMessagesCountLimit = AppSettings.AppSettingsInstance.OfflineMessageCountLimitSetting,
                    //    SendGroupPushWhileOffline = AppSettings.AppSettingsInstance.OfflineGroupToastEnabledSetting,
                    //    SendPmPushWhileOffline = AppSettings.AppSettingsInstance.OfflinePmToastEnabledSetting
                    //}));
                }
                catch { }
            }

        }

        // Code to execute when the application is closing (eg, user hit Back)
        // This code will not execute when the application is deactivated
        private void Application_Closing(object sender, ClosingEventArgs e)
        {
            if (Connection != null)
                Connection.Logout();
            //if (AppSettings.AppSettingsInstance.CustomContactEmoticons != null)
            //{
            //    Dictionary<string, Dictionary<string, string>> dic = new Dictionary<string, Dictionary<string, string>>();
            //    foreach (KeyValuePair<string, Dictionary<string, string>> kvp in AppSettings.AppSettingsInstance.CustomContactEmoticons)
            //    {
            //        Dictionary<string, string> emoticons = new Dictionary<string, string>();
            //        foreach (KeyValuePair<string, string> kvp2 in kvp.Value)
            //        {
            //            if (!String.IsNullOrEmpty(kvp2.Value))
            //                emoticons.Add(kvp2.Key, kvp2.Value);
            //        }
            //        if (emoticons.Count > 0)
            //        {
            //            dic.Add(kvp.Key, emoticons);
            //        }
            //    }
            //    AppSettings.AppSettingsInstance.CustomContactEmoticons = dic;
            //}
            //AppSettings.AppSettingsInstance.CustomEmoticons = AppSettings.AppSettingsInstance.CustomEmoticons;
            //AppSettings.AppSettingsInstance.RecentlyUsedCustomEmoticons = AppSettings.AppSettingsInstance.RecentlyUsedCustomEmoticons;
            //AppSettings.AppSettingsInstance.RecentlyUsedDefaultEmoticons = AppSettings.AppSettingsInstance.RecentlyUsedDefaultEmoticons;
            AppSettings.AppSettingsInstance.Save();
        }

        // Code to execute if a navigation fails
        private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            if (Debugger.IsAttached)
            {
                // A navigation has failed; break into the debugger
                Debugger.Break();
            }
        }

        // Code to execute on Unhandled Exceptions
        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {

            if (Debugger.IsAttached)
            {
                // An unhandled exception has occurred; break into the debugger
                Debugger.Break();
            }
        }

        #region Phone application initialization

        // Avoid double-initialization
        private bool phoneApplicationInitialized = false;

        // Do not add any additional code to this method
        private void InitializePhoneApplication()
        {
            if (phoneApplicationInitialized)
                return;

            // Create the frame but don't set it as RootVisual yet; this allows the splash
            // screen to remain active until the application is ready to render.
            var rootFrame = new TransitionFrame();//PhoneApplicationFrame();
            rootFrame.Background = StaticSettings.BackgroundBrush;
            RootFrame = rootFrame;
            RootFrame.Navigated += CompleteInitializePhoneApplication;

            // Handle navigation failures
            RootFrame.NavigationFailed += RootFrame_NavigationFailed;

            // Handle reset requests for clearing the backstack
            RootFrame.Navigated += CheckForResetNavigation;

            // Ensure we don't initialize again
            phoneApplicationInitialized = true;
        }

        // Do not add any additional code to this method
        private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
        {
            // Set the root visual to allow the application to render
            if (RootVisual != RootFrame)
                RootVisual = RootFrame;

            // Remove this handler since it is no longer needed
            RootFrame.Navigated -= CompleteInitializePhoneApplication;
        }

        private void CheckForResetNavigation(object sender, NavigationEventArgs e)
        {
            // If the app has received a 'reset' navigation, then we need to check
            // on the next navigation to see if the page stack should be reset
            if (e.NavigationMode == NavigationMode.Reset)
                RootFrame.Navigated += ClearBackStackAfterReset;
        }

        private void ClearBackStackAfterReset(object sender, NavigationEventArgs e)
        {
            // Unregister the event so it doesn't get called again
            RootFrame.Navigated -= ClearBackStackAfterReset;

            // Only clear the stack for 'new' (forward) and 'refresh' navigations
            if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh)
                return;

            // For UI consistency, clear the entire page stack
            while (RootFrame.RemoveBackEntry() != null)
            {
                ; // do nothing
            }
        }

        #endregion

        // Initialize the app's font and flow direction as defined in its localized resource strings.
        //
        // To ensure that the font of your application is aligned with its supported languages and that the
        // FlowDirection for each of those languages follows its traditional direction, ResourceLanguage
        // and ResourceFlowDirection should be initialized in each resx file to match these values with that
        // file's culture. For example:
        //
        // AppResources.es-ES.resx
        //    ResourceLanguage's value should be "es-ES"
        //    ResourceFlowDirection's value should be "LeftToRight"
        //
        // AppResources.ar-SA.resx
        //     ResourceLanguage's value should be "ar-SA"
        //     ResourceFlowDirection's value should be "RightToLeft"
        //
        // For more info on localizing Windows Phone apps see http://go.microsoft.com/fwlink/?LinkId=262072.
        //
        private void InitializeLanguage()
        {
            try
            {
                // Set the font to match the display language defined by the
                // ResourceLanguage resource string for each supported language.
                //
                // Fall back to the font of the neutral language if the Display
                // language of the phone is not supported.
                //
                // If a compiler error is hit then ResourceLanguage is missing from
                // the resource file.
                RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage);

                // Set the FlowDirection of all elements under the root frame based
                // on the ResourceFlowDirection resource string for each
                // supported language.
                //
                // If a compiler error is hit then ResourceFlowDirection is missing from
                // the resource file.
                FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection);
                RootFrame.FlowDirection = flow;
            }
            catch
            {
                // If an exception is caught here it is most likely due to either
                // ResourceLangauge not being correctly set to a supported language
                // code or ResourceFlowDirection is set to a value other than LeftToRight
                // or RightToLeft.

                if (Debugger.IsAttached)
                {
                    Debugger.Break();
                }

                throw;
            }
        }
        public static void SetLockscreenState(bool isDisabled)
        {
            Microsoft.Phone.Shell.PhoneApplicationService.Current.UserIdleDetectionMode = isDisabled ? IdleDetectionMode.Disabled : IdleDetectionMode.Enabled;
        }
        public static void ResetTileCount()
        {
            App.unreadMsgCount = 0;
            App.UpdatePrimaryTile(App.unreadMsgCount);
            Connection.SendResetMessageCountMessage();
            //Connection.SendDeviceStatus(MessageType.ResetUnreadMessageCount, StaticMethods.ObjectToString<DeviceInfo>(
            //                new DeviceInfo
            //                {
            //                    IsActive = true,
            //                    IsTileEnabled = AppSettings.AppSettingsInstance.IsTileNotificationEnabledSetting,
            //                    IsToastEnabled = AppSettings.AppSettingsInstance.IsToastNotificationEnabledSetting,
            //                    StoreMessagesWhileOffline = AppSettings.AppSettingsInstance.StoreMessagesWhileOfflineSetting,
            //                    OfflineMessagesAgeLimit = AppSettings.AppSettingsInstance.OfflineMessageAgeLimitSetting,
            //                    OfflineMessagesCountLimit = AppSettings.AppSettingsInstance.OfflineMessageCountLimitSetting
            //                }));
        }
        public static void UpdatePrimaryTile(int count)
        {
            Uri smallIcon = null;
            if (count == 0)
                smallIcon = new Uri("/Assets/1xfeather-110x110px.png", UriKind.RelativeOrAbsolute);
            else
                smallIcon = new Uri("/Assets/1xfeather-70x110px.png", UriKind.RelativeOrAbsolute);
            Uri icon = null;
            if (count == 0)
                icon = new Uri("/Assets/1xfeather-202x202px.png", UriKind.RelativeOrAbsolute);
            else
                icon = new Uri("/Assets/1xfeather-130x202px.png", UriKind.RelativeOrAbsolute);
            IconicTileData primaryTileData = new IconicTileData();
            primaryTileData.Count = count;
            primaryTileData.SmallIconImage = smallIcon;
            primaryTileData.IconImage = icon;

            ShellTile primaryTile = ShellTile.ActiveTiles.First();
            RootFrame.Dispatcher.BeginInvoke(() =>
                {
                    primaryTile.Update(primaryTileData);
                });
        }
        private string GetUniqueId()
        {
            byte[] b = (byte[])DeviceExtendedProperties.GetValue("DeviceUniqueId");
            string str = Convert.ToBase64String(b);
            return "wp8" + str;
        }
        private void Application_RunningInBackground(object sender, RunningInBackgroundEventArgs e)
        {
            //RunningInBackground = true;

            //Debug.WriteLine(DateTime.Now.ToLongTimeString() + ": running in background = true");
        }
        public static void RegisterPush(bool enableTile, bool enableToast)
        {
            if (!Client.Instance.IsLoggedIn)
                return;
            /// Holds the push channel that is created or found.
            HttpNotificationChannel pushChannel = null;

            // The name of our push channel.
            string channelName = "JivePushChannel";

            // Try to find the push channel.
            pushChannel = HttpNotificationChannel.Find(channelName);

            // If the channel was not found, then create a new connection to the push service.
            if (pushChannel == null)
            {
                // return;
                pushChannel = new HttpNotificationChannel(channelName);

                // Register for all the events before attempting to open the channel.
                pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(ToastPushChannel_ChannelUriUpdated);

                pushChannel.Open();

                pushChannel.BindToShellTile();

                pushChannel.BindToShellToast();

            }
            else
            {
                Connection.SendPushUri(pushChannel.ChannelUri.ToString());

                if (!pushChannel.IsShellTileBound)
                    pushChannel.BindToShellTile();
                if (!pushChannel.IsShellToastBound)
                    pushChannel.BindToShellToast();
            }
        }

        void ToastPushChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
        {
            // Error handling logic for your particular application would be here.

            Messenger.Default.Send(String.Format("A push notification {0} error occurred.  {1} ({2}) {3}",
                e.ErrorType, e.Message, e.ErrorCode, e.ErrorAdditionalData));

        }
        private static void ToastPushChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
        {
            HttpNotificationChannel pushChannel = (HttpNotificationChannel)sender;

            Connection.SendPushUri(e.ChannelUri.ToString());
            pushChannel.ChannelUriUpdated -= new EventHandler<NotificationChannelUriEventArgs>(ToastPushChannel_ChannelUriUpdated);
        }
        void ToastPushChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
        {

        }


    }
}